/**
 * 
 */
package qy.jalgotrade.dataseries.resampled;

import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;

import qy.jalgotrade.bar.Bar;
import qy.jalgotrade.bar.BasicBar;
import qy.jalgotrade.utils.resamplebase.Grouper;
import qy.qyalgotrader.utils.Constants;

/**
 * 使用指定的 Bar 作为特定时间周期的第一个 Bar 以及时间周期开始时间, 汇总得到更大级别时间周期的 Bar, 时间周期由 frequency 指定:
 * 
 * @author c-geo
 *
 */
public class BarGrouper extends Grouper<Bar> {

	private double __open;

	private double __high;

	private double __low;

	private double __close;

	private double __volume;

	private double __adjClose;

	private boolean __useAdjValue;

	private Bar.Frequency __frequency;

	private Map<String, Double> __extra;

	private BiFunction<Map<String, Double>, Map<String, Double>, Map<String, Double>> __extraGrouperFun;

	/**
	 * 
	 * @param groupDateTime
	 * @param bar
	 * @param frequency
	 */
	public BarGrouper(ZonedDateTime groupDateTime, Bar bar, Bar.Frequency frequency) {

		this(groupDateTime, bar, frequency,
		        new BiFunction<Map<String, Double>, Map<String, Double>, Map<String, Double>>() {

			        @Override
			        public Map<String, Double> apply(Map<String, Double> oriVal, Map<String, Double> newVal) {

				        // amount:
				        if (oriVal.containsKey(Constants.BAR_FIELD_AMOUNT)
				                && newVal.containsKey(Constants.BAR_FIELD_AMOUNT)) {
					        double oriAmount = oriVal.get(Constants.BAR_FIELD_AMOUNT);
					        double newAmount = newVal.get(Constants.BAR_FIELD_AMOUNT);
					        oriVal.put(Constants.BAR_FIELD_AMOUNT, oriAmount + newAmount);
				        }
				        // position:
				        if (oriVal.containsKey(Constants.BAR_FIELD_POSITION)
				                && newVal.containsKey(Constants.BAR_FIELD_POSITION)) {
					        double newOi = newVal.get(Constants.BAR_FIELD_POSITION);
					        oriVal.put(Constants.BAR_FIELD_POSITION, newOi);
				        }
				        // vwap:
				        /*if (oriVal.containsKey(Constants.BAR_FIELD_VWAP)
				                && newVal.containsKey(Constants.BAR_FIELD_VWAP)) {
				            double oriVwap = oriVal.get(Constants.BAR_FIELD_VWAP);
				            double newVwap = newVal.get(Constants.BAR_FIELD_VWAP);
				            oriVal.put(Constants.BAR_FIELD_VWAP, (oriVwap + newVwap) / 2);
				        }*/

				        return oriVal;
			        }
		        });
	}

	/**
	 * @param groupDateTime
	 * @param bar
	 * @param frequency
	 */
	public BarGrouper(ZonedDateTime groupDateTime, Bar bar, Bar.Frequency frequency,
	        BiFunction<Map<String, Double>, Map<String, Double>, Map<String, Double>> extraGrouperFun) {

		super(groupDateTime);
		__open = bar.getOpen();
		__high = bar.getHigh();
		__low = bar.getLow();
		__close = bar.getClose();
		__volume = bar.getVolume();
		__adjClose = bar.getAdjClose();
		__useAdjValue = bar.getUseAdjValue();
		__frequency = frequency;
		__extra = new HashMap<>();
		__extraGrouperFun = extraGrouperFun;
	}

	/* (non-Javadoc)
	 * @see qy.jalgotrade.utils.resamplebase.Grouper#addValue(java.lang.Object)
	 */
	@Override
	public void addValue(Bar value) {

		if (value.getHigh() > __high) {
			__high = value.getHigh();
		}
		if (value.getLow() < __low) {
			__low = value.getLow();
		}
		__close = value.getClose();
		__adjClose = value.getAdjClose();
		__volume += value.getVolume();
		__extra = __extraGrouperFun.apply(__extra, value.getExtraColumns());
	}

	/* (non-Javadoc)
	 * @see qy.jalgotrade.utils.resamplebase.Grouper#getGrouped()
	 */
	@Override
	public Bar getGrouped() throws Exception {

		Bar ret = new BasicBar(getDateTime(), __open, __high, __low, __close, __volume, __adjClose, __frequency,
		        __extra);
		ret.setUseAdjustedValue(__useAdjValue);
		return ret;
	}
}
